/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2008-2011, Salzburg Research. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * - Neither the name of the KiWi Project nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Contributor(s):
 * Stefan
 *
 * File Info:
 * User: Stefan
 * Date: 2011/01/12
 * Time: 13:53
 *
 * Project: KiWi2, kiwi-knowledgespace module
 */

package kiwi.core.webservices.triplestore;

import kiwi.core.api.content.ContentItemService;
import kiwi.core.api.triplestore.KnowledgeSpaceService;
import kiwi.core.api.triplestore.ResourceService;
import kiwi.core.api.user.UserService;
import kiwi.core.exception.KnowledgeSpaceException;
import kiwi.core.model.Constants;
import kiwi.core.model.rdf.KiWiTriple;
import kiwi.core.model.rdf.KiWiUriResource;
import kiwi.core.qualifiers.transaction.Transactional;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.*;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * User: srobert
 */
@ApplicationScoped
@Path("/kspace/space")
@Produces({"application/json"})
@Transactional
public class KnowledgeSpaceWebService {

    @Inject
    private ContentItemService contentItemService;

    @Inject
    private KnowledgeSpaceService knowledgeSpaceService;

    @Inject
    private Logger log;

    @Inject
    private UserService userService;

    @Inject
    private ResourceService resourceService;

    @GET
    @Path("/tree")
    @Produces("application/json")
    public String treeSpaces() {

        ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
        StringWriter writer = new StringWriter();

        try {
            KiWiUriResource spaceExist = knowledgeSpaceService.getKnowledgeSpaceByTitle("foaf");

            KiWiUriResource s = knowledgeSpaceService.createKnowledgeSpace("foaf");
            KiWiUriResource sp = knowledgeSpaceService.createCategorySpace("Ontology");
            KiWiUriResource sp2 = knowledgeSpaceService.createCategorySpace("Schema");

            if(spaceExist == null) {
                knowledgeSpaceService.updateCategorySpace(s,sp);
                knowledgeSpaceService.updateCategorySpace(sp,sp2);
            }


            mapper.writeValue(writer, convertToPOJOList(knowledgeSpaceService.getRootSpaces(),true));
        } catch(Exception e) {

            log.error(e.getMessage());
        }

        return writer.toString();
    }

    @POST
    @Path("/update/category/{category}")
    @Produces("application/json")
    public String updateCategory(@PathParam("category") String category,@QueryParam("uri") String uri) {

        ObjectMapper mapper = new ObjectMapper();
        StringWriter writer = new StringWriter();

        try {
            KiWiUriResource spaceSub = knowledgeSpaceService.getSpaceByUri(uri);
            KiWiUriResource spaceCategory = knowledgeSpaceService.getCategorySpaceByTitle(category);
            
            if(spaceSub == null || spaceCategory == null) {
                throw new KnowledgeSpaceException("a uri is unknown "+ uri + " " + category);
            }

            knowledgeSpaceService.updateCategorySpace(spaceSub, spaceCategory);


            mapper.writeValue(writer, convertToPOJO(spaceSub,true));
        } catch(Exception e) {

            log.error("Error by updating: " + e.getMessage());
            return null;
        }

        return writer.toString();
    }

    @POST
    @Path("/update/category")
    @Produces("application/json")
    public String updateCategory(@QueryParam("uri") String uri) {

        ObjectMapper mapper = new ObjectMapper();
        StringWriter writer = new StringWriter();

        try {
            KiWiUriResource spaceSub = knowledgeSpaceService.getSpaceByUri(uri);

            if(spaceSub == null) {
                throw new KnowledgeSpaceException("a uri is unknown "+ uri);
            }

            knowledgeSpaceService.updateCategorySpace(spaceSub, null);

            mapper.writeValue(writer, convertToPOJO(spaceSub,true));
        } catch(Exception e) {

            log.error("Error by updating: " + e.getMessage());
            return null;
        }

        return writer.toString();
    }


    @GET
    @Path("/list/root")
    @Produces("application/json")
    public String listRootSpaces() {

        ObjectMapper mapper = new ObjectMapper();
        StringWriter writer = new StringWriter();

        try {

            KiWiUriResource spaceExist = knowledgeSpaceService.getKnowledgeSpaceByTitle("superspace");

            KiWiUriResource s = knowledgeSpaceService.createKnowledgeSpace("superspace");
            KiWiUriResource sp = knowledgeSpaceService.createCategorySpace("test");

            if(spaceExist == null) {
                knowledgeSpaceService.updateCategorySpace(s,sp);
            }

            mapper.writeValue(writer, convertToPOJOList(knowledgeSpaceService.getRootSpaces(),false));
        } catch(Exception e) {

            log.error(e.getMessage());
        }

        return writer.toString();
    }

    @GET
    @Path("/list/children/{title}")
    @Produces("application/json")
    public String listChildrenSpaces(@PathParam("title") String title) {

        ObjectMapper mapper = new ObjectMapper();
        StringWriter writer = new StringWriter();

        try {

            mapper.writeValue(writer, convertToPOJOList(knowledgeSpaceService.getChildren(
                    knowledgeSpaceService.getCategorySpaceByTitle(title)
            ),false));
        } catch(Exception e) {

            log.error(e.getMessage());
        }

        return writer.toString();
    }

    // TODO: Test it
    @GET
    @Path("/list")
    @Produces("application/json")
    public String listSpaces() {

        ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
        StringWriter writer = new StringWriter();

        try {
            knowledgeSpaceService.createKnowledgeSpace("superspace");

            mapper.writeValue(writer, convertToPOJOList(knowledgeSpaceService.getSpaces(),false));
        } catch(Exception e) {

            log.error(e.getMessage());
        }

        return writer.toString();
    }

    // TODO: Test it
    @PUT
    @Path("/add/categoryspace{title}")
    @Produces("application/json")
    public String addKnowledgeSpace(@PathParam("title") String title) {

        return addSpace(title, false);
    }

    // TODO: Test it
    @PUT
    @Path("/add/categoryspace/{title}")
    @Produces("application/json")
    public String addCategorySpace(@PathParam("title") String title) {

        return addSpace(title, true);
    }

    private String addSpace(String title, boolean category) {
        ObjectMapper mapper = new ObjectMapper();
        StringWriter writer = new StringWriter();

        KiWiUriResource newSpace = null;
        try {

            if(knowledgeSpaceService.getCategorySpaceByTitle(title) != null) {
                return null;
            }

            if(category) {

                newSpace = knowledgeSpaceService.createCategorySpace(title);
            } else {

                newSpace = knowledgeSpaceService.createKnowledgeSpace(title);
            }

            mapper.writeValue(writer, convertToPOJO(newSpace,false));

        } catch (Exception e) {

            log.debug("error: " + e.getMessage());
        }

        return writer.toString();
    }

    @PUT
    @Path("/adduri/KnowledgeSpace")
    @Produces("application/json")
    public String addURIKnowledgeSpace(@QueryParam("uri") String uri) {

        return addURISpace(uri, false);
    }

    @PUT
    @Path("/adduri/CategorySpace")
    @Produces("application/json")
    public String addURICategorySpace(@QueryParam("uri") String uri) {

        return addURISpace(uri, true);
    }

    public String addURISpace(String uri, boolean isCategoryspace) {

        ObjectMapper mapper = new ObjectMapper();
        StringWriter writer = new StringWriter();

        KiWiUriResource newSpace = null;
        try {

            if(knowledgeSpaceService.getCategorySpaceByUri(uri) != null) {
                return null;
            }

            if(isCategoryspace) {

                newSpace = knowledgeSpaceService.createCategorySpaceByUri(uri);
            } else {

                newSpace = knowledgeSpaceService.createKnowledgeSpaceByUri(uri);
            }

            mapper.writeValue(writer, convertToPOJO(newSpace,false));

        } catch (Exception e) {

            log.debug("error: " + e.getMessage());
        }

        return writer.toString();
    }

    @Path("/remove")
    @DELETE
    public String removeSpace(@QueryParam("uri") String uri) {

        ObjectMapper mapper = new ObjectMapper();
        StringWriter writer = new StringWriter();

        log.debug("deleting space item with title "+uri);

        KiWiUriResource space = knowledgeSpaceService.getSpaceByUri(uri);
        try {
            knowledgeSpaceService.removeSpaceWithContent(space);
            mapper.writeValue(writer, convertToPOJO(space,false));
        } catch (Exception e) {
            log.error("can not remove space " + e.getMessage());
            return null;
        }

        return writer.toString();
    }

    // TODO: Test it
    @Path("/kind/get/{title}")
    @PUT
    public String getKind(@PathParam("title") String title) {
        log.debug("updating space with title {}", title);

        String kind = getKindOfKnowledgeSpace(
                knowledgeSpaceService.getKnowledgeSpaceByTitle(title));

        return kind;
    }

    private KnowledgeSpacePOJO convertToPOJO(KiWiUriResource space, boolean withChilds) {

        KnowledgeSpacePOJO pojo = new KnowledgeSpacePOJO();

        KiWiUriResource knowledgeSpaceKind = resourceService.createUriResource(KnowledgeSpaceService.SPACE_KNOWLEDGESPACE);

        pojo.setType(Constants.NS_KIWI_CORE_KNOWLEDGESPACE + "categoryspace");

        if (withChilds) {
            List<KiWiUriResource> childs = knowledgeSpaceService.getChildren(space);

            if (childs.size() != 0) {
                pojo.setChildren(convertToPOJOList(childs, withChilds));
            }
        }

        String author = null;
        String creationTime = null;
        String title = null;

        try {
            author = resourceService.getProperty(space, "<"+Constants.NS_KIWI_CORE+"hasAuthor>");
            creationTime = resourceService.getProperty(space, "<"+Constants.NS_KIWI_CORE+"createdOn>");
            title = resourceService.getProperty(space, "<"+Constants.NS_KIWI_CORE+"title>");
        } catch(Exception e) {}

        if(author != null) {
            pojo.setAuthor(author);
        }

        if(creationTime != null) {
            pojo.setCreationTime(creationTime);
        }

        if(knowledgeSpaceService.getCategory(space) != null) {
            pojo.setCategorySpace(knowledgeSpaceService.getCategory(space).getUri());
        }

        if(title != null) {
            pojo.setTitel(title);
        }

        if(space.getUri() != null) {
            pojo.setUri(space.getUri());
        }



        return pojo;
    }

    private List<KnowledgeSpacePOJO> convertToPOJOList(List<KiWiUriResource> spaces, boolean withChilds) {

        List<KnowledgeSpacePOJO> pojos = new ArrayList();

        for(KiWiUriResource pojo : spaces) {

            pojos.add(convertToPOJO(pojo,withChilds));
        }

        return pojos;
    }

    private String getKindOfKnowledgeSpace(KiWiUriResource resource) {

        List<KiWiTriple> triplesOfResource = resourceService.listOutgoing(resource);
        boolean isKnowledgeSpace = false;
        KiWiUriResource knowledgeSpaceKind = resourceService.createUriResource(KnowledgeSpaceService.SPACE_KNOWLEDGESPACE);
        KiWiUriResource kindField = resourceService.createUriResource(KnowledgeSpaceService.SPACE_KIND);

        for(KiWiTriple triple : triplesOfResource) {

            if(triple.getProperty().getUri().equals(Constants.NS_KIWI_CORE_KNOWLEDGESPACE + "publishDateIs") ||
                    triple.getProperty().getUri().equals(Constants.NS_KIWI_CORE_KNOWLEDGESPACE + "publisher") ||
                    triple.getProperty().getUri().equals(Constants.NS_KIWI_CORE_KNOWLEDGESPACE + "publishVersionIs")) {
                return "ontologyspace";
            } else if(((KiWiUriResource)triple.getSubject()).equals(knowledgeSpaceService.getDefaultKnowledgeSpace())) {
                return "defaultspace";
            } else if(((KiWiUriResource)triple.getSubject()).equals(knowledgeSpaceService.getSystemKnowledgeSpace())) {
                return "systemspace";
            } else if(((KiWiUriResource)triple.getSubject()).equals(knowledgeSpaceService.getInferredKnowledgeSpace())) {
                return "inferredspace";
            } else if(triple.getProperty().getUri().equals(Constants.NS_KIWI_CORE_KNOWLEDGESPACE + "owner")) {
                return "userspace";
            } else if(triple.getProperty().getUri().equals(Constants.NS_RDF + "type") && triple.getObject().equals(knowledgeSpaceKind)) {
                isKnowledgeSpace = true;
            } else if(triple.getProperty().getUri().equals(KnowledgeSpaceService.SPACE_KIND)) {
                return "categoryspace";
            }
        }

        return isKnowledgeSpace ? "contentspace" : "somethingelse";
    }


    class KnowledgeSpacePOJO {

        private String author;

        private String titel;

        private String creationTime;

        private String categorySpace;

        private String type;

        private String uri;

        private List<KnowledgeSpacePOJO> children = new ArrayList();

        public String getAuthor() {
            return author;
        }

        public void setAuthor(String author) {
            this.author = author;
        }

        public String getTitel() {
            return titel;
        }

        public void setTitel(String titel) {
            this.titel = titel;
        }

        public String getCreationTime() {
            return creationTime;
        }

        public void setCreationTime(String creationTime) {
            this.creationTime = creationTime;
        }

        public String getCategorySpace() {
            return categorySpace;
        }

        public void setCategorySpace(String categorySpace) {
            this.categorySpace = categorySpace;
        }


        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public List<KnowledgeSpacePOJO> getChildren() {
            return children;
        }

        public void setChildren(List<KnowledgeSpacePOJO> children) {
            this.children = children;
        }

        public String getUri() {
            return uri;
        }

        public void setUri(String uri) {
            this.uri = uri;
        }
    }

}
